﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.ComponentModel;

namespace JetLoginTool
{
    /// <summary>
    /// Does basic Http and Html handling - including Cookie handling!
    /// </summary>
    class HttpHandler
    {
        #region Fields
		private BackgroundWorker bgwWorker;
        private CookieContainer cookieJar;
        private HttpWebResponse returnedResponse;
        private Exception lastException;
        #endregion
        #region Constructors
        /// <summary>
        /// Default Constructor
        /// </summary>
        public HttpHandler()
        {
            bgwWorker = new BackgroundWorker();
            cookieJar = new CookieContainer();
			returnedResponse = null;
			lastException = null;

            bgwWorker.WorkerReportsProgress = true;
            bgwWorker.WorkerSupportsCancellation = true;
            bgwWorker.DoWork += new DoWorkEventHandler(bgwWorker_DoWork);
            bgwWorker.ProgressChanged += new ProgressChangedEventHandler(bgwWorker_ProgressChanged);
            bgwWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwWorker_RunWorkerCompleted);
        }
        #endregion
		#region Properties
		/// <summary>
		/// Gets the last returned HttpWebResponse
		/// </summary>
		public HttpWebResponse ReturnedResponse
		{
			get
			{ return returnedResponse; }
		}

		/// <summary>
		/// Gets the last returned Exception
		/// </summary>
		public Exception LastException
		{
			get
			{ return lastException; }
		}
		#endregion
		#region Public Methods
		/// <summary>
        /// Creates a WebRequest to a given URL with self-managed cookies and no POST vars
        /// </summary>
        /// <param name="url">URL to request</param>
        /// <returns>A HTTPWebRequest for given URL with self-managed cookies and no POST vars</returns>
        public HttpWebRequest nextRequest(string url)
        {
            return makeRequest(url, new Dictionary<string,string>(), cookieJar);
        }

        /// <summary>
        /// Creates a WebRequest to a given URL with POST vars and self-managed cookies
        /// </summary>
        /// <param name="url">URL to request</param>
        /// <param name="postVars">POST vars to pass</param>
        /// <returns>A HTTPWebRequest for given URL with POST vars and self-managed cookies</returns>
        public HttpWebRequest nextRequest(string url, Dictionary<string, string> postVars)
        {
            return makeRequest(url, postVars, cookieJar);
        }

		/// <summary>
		/// Syncronous web call - manages cookies; throws errors
		/// </summary>
		/// <param name="requestToGet">Request to process</param>
		/// <returns>A WebResponse from the call</returns>
		public HttpWebResponse getResponse(HttpWebRequest requestToGet)
		{
			returnedResponse = (HttpWebResponse)requestToGet.GetResponse();
			cookieJar.Add(returnedResponse.Cookies);

			return returnedResponse;
		}

		/// <summary>
		/// Fully managed async web call - managed cookies and errors (return via events)
		/// </summary>
		/// <param name="requestToGet">Request to process</param>
		public void getResponseAsyncStart(HttpWebRequest requestToGet)
		{
			bgwWorker.RunWorkerAsync(requestToGet);
		}
        #endregion
        #region Static Methods
        /// <summary>
        /// Creates a HttpWebRequest given a URL (with no cookies or POST vars)
        /// </summary>
        /// <param name="url">URL to request</param>
        /// <returns>A HTTPWebRequest to the URL; with no cookies or POST vars)</returns>
        public static HttpWebRequest makeRequest(string url)
        {
            return makeRequest(url, new Dictionary<string, string>(), new CookieContainer());
        }

        /// <summary>
        /// Creates a HttpWebRequest given a URL and POST vars (with no cookies)
        /// </summary>
        /// <param name="url">URL to request</param>
        /// <param name="postVars">POST vars to pass with the request</param>
        /// <returns>A HTTPWebRequest to the URL, with POST vars attached; but no cookies</returns>
        public static HttpWebRequest makeRequest(string url, Dictionary<string, string> postVars)
        {
            return makeRequest(url, postVars, new CookieContainer());
        }

        /// <summary>
        /// Creates a HttpWebRequest given the url, post variables and cookies
        /// </summary>
        /// <param name="url">URL to request</param>
        /// <param name="postVars">POST variable to pass in request</param>
        /// <param name="cookies">Cookies to pass in the Request</param>
        /// <returns>A HTTPWebRequest to the URL, with POST vars and Cookies attached</returns>
        public static HttpWebRequest makeRequest(string url, Dictionary<string, string> postVars, CookieContainer cookies)
		{
			HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(url);
			ASCIIEncoding encoder = new ASCIIEncoding();
			byte[] postBytes;
			string postString = "";

			myRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; bgft)";
			myRequest.CookieContainer = cookies;
			myRequest.Method = "POST";
			myRequest.ContentType = "application/x-www-form-urlencoded";

			foreach (string key in postVars.Keys)
			{
				postString += "&" + key + "=" + postVars[key];
			}
			if (postString.Length > 0)
				postString = postString.Substring(1);

			postBytes = encoder.GetBytes(postString);

			myRequest.ContentLength = postBytes.Length;
			Stream requestStream = myRequest.GetRequestStream();
			StreamWriter sw = new StreamWriter(requestStream);
			sw.Write(postString);
			sw.Close();

			return myRequest;
        }

		/// <summary>
		/// Extracts the Response from a HttpWebResponse
		/// </summary>
		/// <param name="inResponse">HttpWebResponse to extract data from</param>
		/// <returns>The response stream, as a string, from the given response</returns>
		public static string responseToString(HttpWebResponse inResponse)
		{
			
			Stream responseStream = inResponse.GetResponseStream();
			StreamReader sr = new StreamReader(responseStream);
			string responseString = sr.ReadToEnd();

			sr.Close();

			return responseString;
		}
        #endregion
        #region EventHandlers
        void bgwWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!e.Cancelled)
            {
				if (e.Result is HttpWebResponse)
                {
                    returnedResponse = (HttpWebResponse)e.Result;
					cookieJar.Add(returnedResponse.Cookies);
                    RaiseHttpWebRequestAsyncFinished();
                }
                else
                {
                    lastException = (Exception)e.Result;
					RaisHttpWebRequestAsynFailed();
                }
            }
        }

        void bgwWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void bgwWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            HttpWebRequest requestToDo = (HttpWebRequest)e.Argument;

            try
            {
                e.Result = requestToDo.GetResponse();
            }
            catch(Exception ex)
            {
                e.Result = ex;
            }
        }
        #endregion
        #region Events
        /// <summary>
        /// Occurs when the Async Web Request has finished
        /// </summary>
        public event EventHandler HttpWebRequestAsyncFinished;
        private void RaiseHttpWebRequestAsyncFinished()
        {
            if (HttpWebRequestAsyncFinished != null)
            {
                HttpWebRequestAsyncFinished.Invoke(this, new EventArgs());
            }
        }

        /// <summary>
        /// Occurs when the Async Web Request does not complete successfully
        /// </summary>
        public event EventHandler HttpWebRequestAsyncFailed;
        private void RaisHttpWebRequestAsynFailed()
        {
            if (HttpWebRequestAsyncFailed != null)
            {
                HttpWebRequestAsyncFailed.Invoke(this, new EventArgs());
            }
        }
        #endregion
    }
}
